package com.codechuan.hallo_internal.floatwindow.log;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.SurfaceTexture;
import android.util.AttributeSet;
import android.view.TextureView;

import androidx.annotation.NonNull;


import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.LinkedBlockingDeque;

public class LogTextureView extends TextureView implements TextureView.SurfaceTextureListener {
    private final Paint clearPaint;
    private int drawTextWidth;
    private final int textHeight;
    private final Paint paint;
    private final LinkedBlockingDeque<LogBean> logs = new LinkedBlockingDeque<>();
    private boolean isRunning = true;
    private boolean isAvailable = true;
    private boolean isDraw = false;
    int maxLines = 15;
    long lines = 0;
    private int paddingLeft;

    public LogTextureView(Context context, AttributeSet attrs) {
        super(context, attrs);
        setSurfaceTextureListener(this);
        setOpaque(false);
        paint = new Paint();
        paint.setColor(Color.WHITE);
        paint.setTextSize(40);
        Paint.FontMetrics fontMetrics = paint.getFontMetrics();
        textHeight = (int) (fontMetrics.descent - fontMetrics.ascent);

        clearPaint = new Paint();
        clearPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        paddingLeft = getPaddingLeft();
        int paddingRight = getPaddingRight();
        drawTextWidth = w - paddingLeft - paddingRight;
    }


    private void drawLogs() {
        Canvas canvas = null;
        try {
            canvas = lockCanvas();
            if (canvas != null) {
                canvas.drawPaint(clearPaint);
                List<String> data = getData();
                int offsetY = 0;
                for (int i = 0; i < data.size(); i++) {
                    String s = data.get(i);
                    paint.setColor(getColor(s));
                    offsetY = (i + 1) * textHeight;
                    drawItem(canvas, s, offsetY);
                    if (isEnd(s)) {
                        LogManager.get().stopLog();
                        return;
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (canvas != null) {
                unlockCanvasAndPost(canvas);
            }
        }
    }

    private List<String> getData() {
        synchronized (logs) {
            ArrayList<LogBean> strings = new ArrayList<>(logs);
            ArrayList<String> result = new ArrayList<>();
            if (strings.isEmpty()) {
                return result;
            }
            if (lines > maxLines) {
                for (long i = lines; i > lines - maxLines; i--) {
                    result.add(0, strings.get((int) (i % strings.size())).getMessage());
                }
            } else {
                for (int i = 0; i < lines; i++) {
                    result.add(strings.get(i % strings.size()).getMessage());
                }
            }
            lines++;
            return result;
        }
    }

    private void drawItem(Canvas canvas, String logText, int y) {
        canvas.drawText(logText, paddingLeft, y, paint);
    }

    private boolean isEnd(String logText) {
        return logText.contains("未刷脸");
    }

    private int getColor(String logText) {
        if (logText.contains("成功加入PK")) {
            return Color.GREEN;
        } else if (logText.contains("接单成功")) {
            return Color.RED;
        }
        return Color.WHITE;
    }

    private void drawBackground() {
        Canvas canvas = null;
        try {
            canvas = lockCanvas();
            if (canvas != null) {
                canvas.drawColor(Color.TRANSPARENT);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (canvas != null) {
                unlockCanvasAndPost(canvas);
            }
        }
    }


    @Override
    public void onSurfaceTextureAvailable(@NonNull SurfaceTexture surface, int width, int height) {
        isAvailable = true;
        start();
    }

    @Override
    public void onSurfaceTextureSizeChanged(@NonNull SurfaceTexture surface, int width, int height) {

    }

    @Override
    public boolean onSurfaceTextureDestroyed(@NonNull SurfaceTexture surface) {
        isAvailable = false;
        stop();
        return true;
    }

    @Override
    public void onSurfaceTextureUpdated(@NonNull SurfaceTexture surface) {

    }

    void addLog(String message) {
        synchronized (logs) {
            int size;
            if (logs.size() > maxLines && logs.size() - maxLines >= (size = logs.getFirst().getSize())) {
                for (int i = 0; i < size; i++) {
                    logs.pollFirst();
                }
            }
            List<String> splitLines = getSplitLines(message);
            for (String splitLine : splitLines) {
                logs.offer(new LogBean(splitLines.size(), splitLine));
            }
        }
    }

    private List<String> getSplitLines(String message) {
        ArrayList<String> result = new ArrayList<>();
        int start = 0;
        while (start < message.length()) {
            int count = paint.breakText(message, start, message.length(), true, drawTextWidth, null);
            result.add(message.substring(start, start + count));
            start += count;
        }
        return result;
    }


    synchronized void start() {
        isRunning = true;
        if (isDraw) {
            return;
        }
        new Thread(() -> {
            while (isRunning && isAvailable) {
                isDraw = true;
                drawBackground();
                drawLogs();
                try {
                    Thread.sleep(50);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
            isDraw = false;
        }).start();
    }

    void stop() {
        logs.clear();
        isRunning = false;
        isDraw = false;
    }
}
